// #pragma once

#ifndef _SLIC_H_UTILS_
#define _SLIC_H_UTILS_

// #include <cstring>
// #include <Eigen/Dense>
#include <x86intrin.h>
// #define _GNU_SOURCE      /* These two lines are optional. They are only
// needed to use the scalar */
#include <atomic>
#include <math.h> /* functions sin, exp, sincos,...                                       */
#include <mutex>
#include <stack>
#include <thread>
#include <unordered_map>
#include <vector>
extern "C" {
__m256d _ZGVdN4vv_pow(__m256d x, __m256d y);
}

#define CHAR_DOUBLE_AMAX 127
// double char_double_amax[1];
// memset(char_double_amax, CHAR_DOUBLE_AMAX, sizeof(double));
// namespace Eigen {
// typedef Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
// Eigen::RowMajor>
//     rMatrixXd;
// }

static int only_once = 1;
static int only_once2 = 1;
static int some_times1 = 100;

// typedef unsigned int suint;

#define BLOCKSIZE_C 32
#define UNROLL 4
#define CONV_MM
// #define __INTEL_COMPILER
#define THE_THREAD_NUMS_COVT 32
#define THE_THREAD_NUMS_EDGES 16
#define THE_THREAD_NUMS_DIST THE_THREAD_NUMS_COVT
#define THE_THREAD_NUMS_SIGMA THE_THREAD_NUMS_DIST
#define THE_THREAD_NUMS_ENFORCE THE_THREAD_NUMS_COVT

#define BLOCK_SIZE_SIGMA 8
#define BLOCK_SIZE_DetectLabEdgesY 4
#define BLOCK_SIZE_DetectLabEdgesX 4


template <class T> T *align_new(unsigned int n, unsigned int align_size) {
  char *ptr, *ptr2, *aligned_ptr;
  int align_mask = align_size - 1;

  ptr = new char[n * sizeof(T) + align_size + sizeof(int)];
  if (ptr == 0)
    return 0;

  ptr2 = ptr + sizeof(int);
  aligned_ptr = ptr2 + (align_size - ((size_t)ptr2 & align_mask));

  ptr2 = aligned_ptr - sizeof(int);
  *((int *)ptr2) = (int)(aligned_ptr - ptr);

  return (T *)aligned_ptr;
}

template <class T> void align_delete(T *ptr) {
  int *ptr2 = (int *)ptr - 1;
  char *p;

  p = (char *)ptr;
  p -= *ptr2;
  delete[] p;
}

// void dist_update_block(double *lvec, double *avec, double *bvec, int width,
//                        int sy, int sx, double *distlab, double *distxy,
//                        double *distvec, double *klabels, double kseedsl,
//                        double kseedsa, double kseedsb, double kseedsx,
//                        double kseedsy) {
//   int x = sx;
//   for (; x < sx + BLOCKSIZE; x += UNROLL * 4) {
//     int y = sy;
//     for (; y < sy + BLOCKSIZE; y++) {
//       __m256d l0[UNROLL];
//       __m256d a0[UNROLL];
//       __m256d b0[UNROLL];
//       for (int cc = 0; cc < UNROLL; cc++) {
//         l0[cc] = _mm256_load_pd(lvec + x + y * width + cc * 4);
//         a0[cc] = _mm256_load_pd(avec + x + y * width + cc * 4);
//         b0[cc] = _mm256_load_pd(bvec + x + y * width + cc * 4);
//       }
//     }
//   }
// }

struct RGB {
  char *r;
  char *g;
  char *b;
};

static int count_rb = 0;
static int count_rs = 0;
// const double
static double count_time1 = 0;
static double count_time2 = 0;
static double count_time3 = 0;
static double count_time4 = 0;
static double count_time5 = 0;

static int xrcc(0), yrcc(0), zrcc(0);

#define DOUBLE_AVX2 4

template <typename T>
void update_sigma(T *sigmal, T *sigmaa, T *sigmab, T *sigmax, T *sigmay,
                  int *clustersize, int *klabels, T *m_lvec, T *m_avec,
                  T *m_bvec, int sz, int m_width, int m_height, T *sigmalab,
                  T *m_labz) {
  // #pragma omp parallel for
  // 左边 numk 个，右边 sz 个，导致左值严重的访存冲突
  // 并行需保证正确性，效率低
  for (int y = 0; y < m_height; y++) {
    const int yindex = y * m_width;
    for (int x = 0; x < m_width; x++) {
      const int index = (yindex + x);
      const int kl = klabels[index];
      sigmal[kl] += m_lvec[index];
      sigmaa[kl] += m_avec[index];
      sigmab[kl] += m_bvec[index];
      sigmax[kl] += x;
      sigmay[kl] += y;

      clustersize[kl]++;
    }
  }
  // for (int j = 0; j < sz; j++) {
  //   // int temp = klabels[j];
  //   // int index = klabels[j] * 4;
  //   //_ASSERT(klabels[j] >= 0);
  //   // __m256d mm_labz = _mm256_load_pd(m_labz + index);
  //   // __m256d mm_sigmalab = _mm256_load_pd(sigmalab + index);
  //   // _mm256_store_pd(sigmalab + index, _mm256_add_pd(mm_labz,
  //   mm_sigmalab)); sigmal[klabels[j]] += m_lvec[j]; sigmaa[klabels[j]] +=
  //   m_avec[j]; sigmab[klabels[j]] += m_bvec[j]; sigmax[klabels[j]] += (j %
  //   m_width); sigmay[klabels[j]] += (j / m_width);

  //   clustersize[klabels[j]]++;
  // }
}

static std::mutex union_find_mtx;
int union_find(int *array, int index);

// static int getLabel_label = 0;
// static std::stack<int> getLabel_stack;
// std::mutex getLabel_mtx;
// int getLabel() {
//   std::lock_guard<std::mutex> lk(getLabel_mtx);
//   if (getLabel_stack.size() > 0) {
//     int tmp = getLabel_stack.top();
//     getLabel_stack.pop();
//     return tmp;
//   } else {
//     return getLabel_label++;
//   }
// }
// void returnLabel(int label){
//   std::lock_guard<std::mutex> lk(getLabel_mtx);
//   getLabel_stack.push(label);
// }


#endif